﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Control.cs" company="Marcelo Roca">
//   Copyright (c) 2011 Marcelo Roca. All rights reserved.
// </copyright>
// <author name="Marcelo Roca" email="marce@marceloroca.com"/>
// <license>
//   This program is free software: you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
// 
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program.  If not, see http://www.gnu.org/licenses/.
// </license>
// --------------------------------------------------------------------------------------------------------------------

namespace GameKits.Unity.GuiForms.Controls
{
    using UnityEngine;

    public abstract class Control
    {
        #region Private Variables

        /// <summary>
        /// el content del control
        /// </summary>
        private readonly GUIContent content = new GUIContent();

        /// <summary>
        /// El id del control
        /// </summary>
        private readonly string id = System.Guid.NewGuid().ToString();

        /// <summary>
        /// el color del gui
        /// </summary>
        private RgbColor color = new RgbColor(1, 1, 1);

        /// <summary>
        /// el alineamiento horizontal
        /// </summary>
        private HorizontalAlignment horizontalAlignment;

        /// <summary>
        /// indica si el control es visible
        /// </summary>
        private bool isVisible = true;

        /// <summary>
        /// Indica si el control está habilitado o no
        /// </summary>
        private bool isEnabled = true;

        /// <summary>
        /// la opacidad del control
        /// </summary>
        private float opacity = 1;

        /// <summary>
        /// indica que se debe tomar el foco del control
        /// </summary>
        private bool setFocus;

        /// <summary>
        /// The guiskin
        /// </summary>
        private GUISkin skin;

        /// <summary>
        ///  el estilo del control
        /// </summary>
        private GUIStyle style;

        /// <summary>
        /// el alineamiento vertical
        /// </summary>
        private VerticalAlignment verticalAlignment;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Control"/> class.
        /// </summary>
        protected Control()
        {
            this.Parent = null;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets Opacity.
        /// </summary>
        public RgbColor Color
        {
            get { return this.color; }
            set { this.color = value; }
        }

        /// <summary>
        /// Gets or sets HorizontalAlignment.
        /// </summary>
        public HorizontalAlignment HorizontalAlignment
        {
            get
            {
                return this.horizontalAlignment;
            }

            set
            {
                if (this.horizontalAlignment != value)
                {
                    this.horizontalAlignment = value;
                    this.IsDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets the control Id.
        /// </summary>
        public string Id
        {
            get { return this.id; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether IsEnabled.
        /// </summary>
        public bool IsEnabled
        {
            get { return this.isEnabled; }
            set { this.isEnabled = value; }
        }

        /// <summary>
        /// Gets a value indicating whether IsInitialized.
        /// </summary>
        public bool IsInitialized { get; private set; }

        /// <summary>
        /// Gets or sets a value indicating whether IsVisible.
        /// </summary>
        public bool IsVisible
        {
            get { return this.isVisible; }
            set { this.isVisible = value; }
        }

        /// <summary>
        /// Gets or sets Opacity.
        /// </summary>
        public float Opacity
        {
            get { return this.opacity; }
            set { this.opacity = value; }
        }

        /// <summary>
        /// Gets Parent.
        /// </summary>
        public IContainer Parent { get; internal set; }

        /// <summary>
        /// Gets or sets Skin.
        /// </summary>
        public GUISkin Skin
        {
            get
            {
                if (this.skin == null)
                {
                    if (this.Parent != null)
                    {
                        return this.Parent.Skin;
                    }
                }

                return null;
            }

            set
            {
                if (this.skin != value)
                {
                    this.skin = value;
                    this.IsDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets or sets Style.
        /// </summary>
        /// <remarks>
        /// The style to use. If left out, the box style from the current GUISkin is used.
        /// </remarks>
        public GUIStyle Style
        {
            get
            {
                return this.style;
            }

            set
            {
                if (this.style != value)
                {
                    this.style = value;
                    this.IsDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether ShowToolTip.
        /// </summary>
        public bool ShowToolTip { get; set; }

        /// <summary>
        /// Gets or sets Tag.
        /// </summary>
        public object Tag { get; set; }

        /// <summary>
        /// Gets or sets ToolTip.
        /// </summary>
        public string ToolTip { get; set; }

        /// <summary>
        /// Gets or sets VerticalAlignment.
        /// </summary>
        public VerticalAlignment VerticalAlignment
        {
            get
            {
                return this.verticalAlignment;
            }

            set
            {
                if (this.verticalAlignment != value)
                {
                    this.verticalAlignment = value;
                    this.IsDirty = true;
                }
            }
        }

        /// <summary>
        /// Gets Content.
        /// </summary>
        protected GUIContent Content
        {
            get { return this.content; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether IsDirty.
        /// </summary>
        protected bool IsDirty { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Move keyboard focus to a named control.
        /// </summary>
        public void SetFocus()
        {
            this.setFocus = true;
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// REalizamos el GUI
        /// </summary>
        internal void DoOnGui()
        {
            if (!this.IsInitialized)
            {
                this.Initialize();
            }

            if (!this.IsVisible)
            {
                return;
            }

            if (this.IsDirty)
            {
                this.DoOnLayout();
            }

            var be = GUI.enabled;
            var bc = GUI.color;

            GUI.enabled = this.Parent.IsEnabled && this.IsEnabled;
            GUI.color = this.Color.ToColor(this.Opacity * bc.a);

            GUI.SetNextControlName(this.Id);

            this.DrawControl();

            if (this.setFocus)
            {
                this.setFocus = false;
                GUI.FocusControl(this.Id);  
            }

            GUI.enabled = be;
            GUI.color = bc;
        }

        /// <summary>
        /// Realiza el layout del control
        /// </summary>
        protected virtual void DoOnLayout()
        {
            if (this.IsDirty)
            {
                this.OnLayout();
                this.IsDirty = false;
            }
        }

        /// <summary>
        /// Se debe implementar para pintar el control
        /// </summary>
        protected abstract void DrawControl();

        /// <summary>
        /// Realizar la inicialización del control
        /// </summary>
        protected void Initialize()
        {
            this.OnInitialize();
            this.IsInitialized = true;
        }

        /// <summary>
        /// El control debe realizar el re-calculo del layout
        /// </summary>
        protected virtual void OnLayout()
        {
        }

        /// <summary>
        /// El controls debe realizar la inciialización
        /// </summary>
        protected virtual void OnInitialize()
        {
        }

        #endregion
    }
}

